<!--
 * @Author: 周云芳 164591357@qq.com
 * @Date: 2022-08-15 09:37:02
 * @LastEditors: 周云芳 164591357@qq.com
 * @LastEditTime: 2022-08-15 11:50:57
 * @FilePath: \canvas-flowers\bloom.html
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>花朵绽放</title>
    <style>
        body,
        html {
            width: 100%;
            height: 100%;
            padding: 0;
            margin: 0;
            background-color: #000;
        }

        /* canvas {
            background-color: #ddd;
            width: 100%;
            height: 100vh;
        } */
    </style>
</head>

<body>
    <canvas></canvas>
    <script>
        // 把每片花瓣放入数组
        let branchArr = []
        // 定义色相值
        let startHue = 0
        // canvas相关的属性封装成一个对象
        let canvas = {
            init () {
                this.oC = document.querySelector('canvas')
                let cxt = this.oC.getContext('2d')
                this.resize()
                window.addEventListener('resize', function(e) {
                    canvas.resize()
                })
                return cxt
            },
            resize () {
                this.width = this.oC.width = document.body.offsetWidth
                this.height = this.oC.height = document.body.offsetHeight
            }
        }
        let cxt = canvas.init()
        // 设置随机范围,返回一个大于min,小于max的一个随机数
        function rand (min, max) {
            return Math.random() * (max - min) + min
        }
        // 定义花瓣的衍生过程中class属性
        class Branch {
            constructor(hue) {
                this.hue = hue
                let distance = 15//加个距离防止所有花瓣散出来的时候都从一个点位防止拥挤
                this.x = canvas.width / 2 + rand(-distance, distance)
                this.y = canvas.height / 2 + rand(-distance, distance)
                this.angle = rand(0, Math.PI * 2)//设置一个360角度,让花瓣随机散开
                this.spread = 0//改变花瓣芯散开角度让其弯曲,避免一直像一条线一样不好看
                this.v = rand(-6, 6)//设置花瓣散开的速度 
                this.life = 1//花瓣的生命值,什么时候停止延生
                this.decay = 0.0015//生命衰减值(慢慢枯萎颜色变淡)
                this.points = [{//设置坐标,让其记录坐标值,下次的衍生在上一次的基础上
                    x: this.x,
                    y: this.y
                }]
            }
            // 绘制轨迹,改变坐标
            step () {
                //从移动的时候起开始设置衰减系数
                this.life -= this.decay
                if (!(this.life < 0)) {//当小于0的时候获取最后一个坐标为起始坐标
                    let lastPoint = this.points[this.points.length - 1]
                    let newPoint = {
                        x: lastPoint.x + Math.cos(this.angle) * this.v,
                        y: lastPoint.y + Math.sin(this.angle) * this.v
                    }
                    // 加入坐标中成为下一个坐标起点往外衍生
                    this.points.push(newPoint)
                    this.v *= 0.99//让散开的速度越来越慢
                    this.angle += rand(-this.spread, this.spread)//再对衍生角度弯曲进行设置
                    this.spread = this.v * 0.04//在对花瓣到最后的时候角度散开越来越小接近直线
                    this.hue += 0.3//在最后的衰减上让色相值变亮些
                }
            }
            // 绘制方法
            draw (cxt) {
                // 如果生命值小于0就不绘制了
                if (this.life < 0) {
                    return
                }
                // 不小于0就绘制,在最后一个坐标值上衍生
                let lastPoint = this.points[this.points.length - 1]
                // 随机取出前一个点坐标
                let beforePoint = this.points[(this.points.length - 1) - Math.floor(rand(5, 100))]
                if (beforePoint) {//开始绘制
                    // console.log('开始绘制', beforePoint);
                    cxt.beginPath()
                    // 衍生到最后的时候速度越来越慢为了防止最后的起始点和经过点重叠加,加入一个抖动效果随机数
                    let jitter = 2 + this.v * 6//最小为2最大为8
                    cxt.moveTo(beforePoint.x, beforePoint.y)//从最后一个坐标点的随机位置开始绘制
                    cxt.lineTo(lastPoint.x + rand(-jitter, jitter), lastPoint.y + rand(-jitter, jitter))//经过最后一个坐标点
                    let alpha = this.life * 0.05//设置透明度,在花尖上最亮
                    cxt.strokeStyle = `hsla(${this.hue},70%,40%,${alpha})`
                    cxt.stroke()
                }
            }
        }
        // 生成花瓣数量 
        function generateBranch () {
            let num = 500
            while (num--) {
                branchArr.push(new Branch(startHue))
            }
        }
        generateBranch()
        function play () {
            for (let i = 0, len = branchArr.length; i < len; i++) {
                const branch = branchArr[i];
                branch.step() // 绘制轨迹,改变坐标
                branch.draw(cxt)  // 绘制样式
            }
            requestAnimationFrame(play)
        }
        // 点击的时候重新绘制
        window.addEventListener('click', function(e) {
            canvas.resize()
            startHue += 60
            branchArr = []
            generateBranch()
            play()

        })
        play() 
    </script>
</body>

</html>